﻿// This File is part of Innovation Foundry's "QualityHelper Project"
//
// Copyright  2009 Innovation Foundry Pty Ltd
// All rights reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA  02110-1301 USA
// or alternatively it may be downloaded from <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Windows.Controls;

using InnovationFoundry.QualityHelper.Silverlight.Controls.FishEyeMenu;
using InnovationFoundry.QualityHelper.Silverlight.Assets.Resources;
using InnovationFoundry.QualityHelper.Silverlight.Controls.ProcedureScroll;
using InnovationFoundry.QualityHelper.Silverlight.Layout;
using InnovationFoundry.QualityHelper.Silverlight.Controls.Zoom;
using InnovationFoundry.QualityHelper.Silverlight.Utilities;
using InnovationFoundry.QualityHelper.Silverlight.BLL.Objects;
using InnovationFoundry.QualityHelper.Silverlight.BLL;
using InnovationFoundry.QualityHelper;
using InnovationFoundry.QualityHelper.Utilities;



namespace InnovationFoundry.QualityHelper.Silverlight
{
    [ScriptableType]
    public partial class MainPage : UserControl
    {
        ObservableCollection<DocumentObject> documentList = new ObservableCollection<DocumentObject>();
        ObservableCollection<ProcedureObject> procedureList = new ObservableCollection<ProcedureObject>();
        ObservableCollection<ProcedureObject> searchResultsProcedures = new ObservableCollection<ProcedureObject>();

        string rootProcedureID = null; 
        string lastProcedureIDClicked = null;
        string lastProcedureID = null;
        private DocumentObject nullDocument = new DocumentObject("No documents");
        private delegate void DiagramProcessed(object sender, string diagramID);
        private event DiagramProcessed DiagramProcessedEvent;


        public MainPage()
        {
            HtmlPage.RegisterScriptableObject("SilverlightQualityHelper", this);
            InitializeComponent();
            flowControl.ProcedureClicked += new InnovationFoundry.QualityHelper.Silverlight.Controls.CoverFlow.CoverFlowControl.ProcedureClickedHandler(flowControl_ProcedureClicked);
            flowControl.ProcedureDoubleClicked += new InnovationFoundry.QualityHelper.Silverlight.Controls.CoverFlow.CoverFlowControl.ProcedureDoubleClickedHandler(flowControl_ProcedureDoubleClicked);
            flowControl.CoverFlowChangedEvent += new InnovationFoundry.QualityHelper.Silverlight.Controls.CoverFlow.CoverFlowControl.CoverFlowChanged(flowControl_CoverFlowChangedEvent);
            ReferencesOut.ProcedureClicked += new InnovationFoundry.QualityHelper.Silverlight.Controls.ProcedureScroll.ProcedureScroll.ProcedureScrollClickedHandler(ReferencesOut_ProcedureClicked);
            ReferencesIn.ProcedureClicked += new InnovationFoundry.QualityHelper.Silverlight.Controls.ProcedureScroll.ProcedureScroll.ProcedureScrollClickedHandler(ReferencesIn_ProcedureClicked);
            Application.Current.Host.Content.Resized += new EventHandler(Content_Resized);
            this.DiagramProcessedEvent += new DiagramProcessed(MainPage_DiagramProcessedEvent);
            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
            searchResultProceduresSmall.ItemsSource = searchResultsProcedures;
            documentList.Add(nullDocument);
            treeDocs.ItemsSource = documentList;
            UpdateRootDiagram();
            ResetDiagrams(HtmlPage.Window.Invoke("getLastProcedureClicked") as string);

        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {

            string appIcon = HtmlPage.Window.Invoke("GetApplicationIcon") as string;
            BitmapImage imgUri = new BitmapImage(new Uri(URIHelper.GetAbsoluteUri(appIcon), UriKind.Absolute));
            if (appIcon != null)
                AppIcon.Source = imgUri;

            string appAlias = HtmlPage.Window.Invoke("GetApplicationAlias") as string;
            if (appAlias != null)
                AppTitle.Text = appAlias;

            string appBG = HtmlPage.Window.Invoke("GetApplicationBG") as string;
            if (appBG != null)
            {
                BitmapImage bgImgUri = new BitmapImage();
                bgImgUri.UriSource = new Uri(URIHelper.GetAbsoluteUri(appBG), UriKind.Absolute);
                ImageBrush bgImgBrush = new ImageBrush();
                bgImgBrush.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(bgImgBrush_ImageFailed);
                bgImgBrush.ImageSource = bgImgUri;
                LayoutRoot.Background = bgImgBrush;
            }
            else
                bgImgBrush_ImageFailed(null, null);

            expanderAscendents.SizeChanged +=new DragDropExpander.SizeChangedHandler(expander_SizeChanged);
            expanderDescendents.SizeChanged += new DragDropExpander.SizeChangedHandler(expander_SizeChanged);
            expanderDocs.SizeChanged += new DragDropExpander.SizeChangedHandler(expander_SizeChanged);
            expanderProcInfo.SizeChanged += new DragDropExpander.SizeChangedHandler(expander_SizeChanged);
            expanderSmallSearchDocs.SizeChanged += new DragDropExpander.SizeChangedHandler(expander_SizeChanged);
            expanderSmallSearchProcs.SizeChanged += new DragDropExpander.SizeChangedHandler(expander_SizeChanged);

            expanderAscendents.RequiresAttachment +=new EventHandler(expander_RequiresAttachment);
            expanderDescendents.RequiresAttachment +=new EventHandler(expander_RequiresAttachment);
            expanderDocs.RequiresAttachment += new EventHandler(expander_RequiresAttachment);
            expanderProcInfo.RequiresAttachment += new EventHandler(expander_RequiresAttachment);
            expanderSmallSearchDocs.RequiresAttachment += new EventHandler(expander_RequiresAttachment);
            expanderSmallSearchProcs.RequiresAttachment += new EventHandler(expander_RequiresAttachment);

            expanderAscendents.RequiresDetachment += new EventHandler(expander_RequiresDetachment);
            expanderDescendents.RequiresDetachment += new EventHandler(expander_RequiresDetachment);
            expanderDocs.RequiresDetachment += new EventHandler(expander_RequiresDetachment);
            expanderProcInfo.RequiresDetachment += new EventHandler(expander_RequiresDetachment);
            expanderSmallSearchDocs.RequiresDetachment += new EventHandler(expander_RequiresDetachment);
            expanderSmallSearchProcs.RequiresDetachment += new EventHandler(expander_RequiresDetachment);

        }

        void bgImgBrush_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            BitmapImage bgImgUri = new BitmapImage();
            bgImgUri.UriSource = new Uri("background.jpg", UriKind.Relative);
            ImageBrush bgImgBrush = new ImageBrush();
            bgImgBrush.ImageSource = bgImgUri;
            LayoutRoot.Background = bgImgBrush;
        }

        void expander_RequiresAttachment(object sender, EventArgs args)
        {
            //not implemented yet
            DragDropExpander dde = sender as DragDropExpander;
            if (dde == null)
                return;
            Canvas c = dde.Parent as Canvas;
            if (c == null)
                return;
            StackPanel p = dde.OriginalParent as StackPanel;
            if (p != null)
            {
                PageRoot.Children.Remove(c);
                dde.OriginalP = new Point(0, 0);
                dde.IsAttached = true;
                dde.Margin = new Thickness(0, 0, 0, 0);
                p.Children.Add(c);
            }

        }

        void expander_RequiresDetachment(object sender, EventArgs args)
        {
            DragDropExpander dde = sender as DragDropExpander;
            if (dde == null)
                return;
            Canvas c = dde.Parent as Canvas;
            if (c == null)
                return;
            StackPanel p = c.Parent as StackPanel;
            if (p != null)
            {
                dde.OriginalParent = p;
                dde.OriginalP = p.TransformToVisual(PageRoot).Transform(new Point(0, 0));
                Point relativeDistance = dde.TransformToVisual(PageRoot).Transform(new Point(0, 0));
                p.Children.Remove(c);
                dde.IsAttached = false;
                dde.Margin = new Thickness(relativeDistance.X, relativeDistance.Y, 0, 0);
                PageRoot.Children.Add(c);

            }
        }

        void expander_SizeChanged(object sender, Size finalSize)
        {
            DragDropExpander dde = sender as DragDropExpander;
            if (dde == null)
                return;
            Canvas c = dde.Parent as Canvas;
            if (c != null)
            {
                c.Height = finalSize.Height;
                //c.Width = finalSize.Width;
            }
           
        }

        void expander_ParentResizing(DragDropExpander dde)
        {
            if (dde == null)
                return;
            Canvas c = dde.Parent as Canvas;
            if (c == null)
                return;
            if (dde.OriginalParent != null && !dde.IsAttached)
            {
                dde.OriginalP = (dde.OriginalParent as StackPanel).TransformToVisual(PageRoot).Transform(new Point(0, 0));
            }
        }

        void Content_Resized(object sender, EventArgs e)
        {
            double toSubtract = 50;
            double height = Application.Current.Host.Content.ActualHeight - toSubtract;
            height = (height < 225) ? 225 : height;
            
            expanderDocs.MaxHeight = height / 2;
            
            expanderProcInfo.MaxHeight = height / 3;

            expanderSmallSearchDocs.MaxHeight = height / 3;

            expanderSmallSearchProcs.MaxHeight = height / 3;

            expanderDescendents.MaxHeight = height / 2;

            expanderAscendents.MaxHeight = height / 2;

            //ddpDocs.MaxHeight = expanderDocs.MaxHeight;
            //ddpProcInfo.MaxHeight = expanderProcInfo.MaxHeight;
            //ddpSmallSearchDocs.MaxHeight = expanderSmallSearchDocs.MaxHeight;
            //ddpSmallSearchProcs.MaxHeight = expanderSmallSearchProcs.MaxHeight;
            //ddpDescendents.MaxHeight = expanderDescendents.MaxHeight;

            double width = 250;
            expanderAscendents.Width = width;
            expanderDocs.Width = width;

            expanderDescendents.Width = width;
            expanderProcInfo.Width = width;
            expanderSmallSearchDocs.Width = width;
            expanderSmallSearchProcs.Width = width;

            expander_ParentResizing(expanderAscendents);
            expander_ParentResizing(expanderDescendents);
            expander_ParentResizing(expanderDocs);
            expander_ParentResizing(expanderProcInfo);
            expander_ParentResizing(expanderSmallSearchDocs);
            expander_ParentResizing(expanderSmallSearchProcs);


        }

        void updateMenus()
        {
            stackPanelLeft.InvalidateArrange();
            stackPanelRight.InvalidateArrange();

        }


        void ReferencesIn_ProcedureClicked(object sender, ProcedureScroll.ProcedureScrollClickedArgs args)
        {
            AddDiagramToCoverflowCache(args.Procedure.ProcedureID);
            lastProcedureID = args.Procedure.ProcedureID;
            flowControl.PrependDiagram(args.Procedure.ProcedureID, args.ProcedureRelation, false);
            flowControl.UpdateFlowByProcedure(args.Procedure.ProcedureID);
            updateProcedureInfo(args.Procedure);
            ReferencesIn.ClearProcedures();
            UpdateDocuments(args.Procedure.ProcedureID);
            canvasAscendents.Visibility = Visibility.Collapsed;
            canvasDescendents.Visibility = Visibility.Collapsed;
            updateMenus();
        }

        void ReferencesOut_ProcedureClicked(object sender, ProcedureScroll.ProcedureScrollClickedArgs args)
        {
            AddDiagramToCoverflowCache(args.Procedure.ProcedureID);
            lastProcedureID = args.Procedure.ProcedureID;
            flowControl.AppendDiagram(args.Procedure.ProcedureID, args.ProcedureRelation, false);
            flowControl.UpdateFlowByProcedure(args.Procedure.ProcedureID);
            updateProcedureInfo(args.Procedure);
            ReferencesOut.ClearProcedures();
            UpdateDocuments(args.Procedure.ProcedureID);
            canvasAscendents.Visibility = Visibility.Collapsed;
            canvasDescendents.Visibility = Visibility.Collapsed;
            updateMenus();
        }

        void flowControl_CoverFlowChangedEvent(object sender, object diagramID)
        {
            //TODO:
            //Clear the reference history
        }

        void MainPage_DiagramProcessedEvent(object sender, string diagramID)
        {
            //Check the ID
            //diagram
            if (flowControl.ProcedureExistsInDiagram(lastProcedureID,diagramID))
                flowControl.UpdateFlow(diagramID);
        }

        [ScriptableMember()]
        public void ProcessDiagram(object diag)
        {
            DiagramObject diagram = ParserHelper.ParseDiagram(diag);
            if (diagram == null)
                return;
            flowControl.AddDiagramToCache(diagram);
            if (DiagramProcessedEvent != null)
                DiagramProcessedEvent(this, diagram.DiagramID);
        }

        private void UpdateRootDiagram()
        {
            rootProcedureID = String.Format("{0}", HtmlPage.Window.Invoke("GetRootProcedureID"));
            if (rootProcedureID == null || string.Empty == rootProcedureID)
                rootProcedureID = null;
        }


        [ScriptableMember]
        public void SearchProcedures(string searchTerm)
        {
            //documentList.Add(result);
            HtmlPage.Window.Invoke("searchProcedures", searchTerm);
        }

        [ScriptableMember]
        public void SearchProceduresCallback(object procedureArray, string searchTerm)
        {
            if (searchTerm == txtSearch.Text)
            {
                ObservableCollection<ProcedureObject> procs = BLL.ParserHelper.ParseProcedures((ScriptObject)procedureArray);
                foreach (ProcedureObject proc in procs)
                {
                    if (!searchResultsProcedures.Any(sr => sr.ProcedureID == proc.ProcedureID))
                        searchResultsProcedures.Add(proc);
                }
                if (searchResultsProcedures.Count > 0)
                {
                    canvasSmallSearchProcs.Visibility = Visibility.Visible;
                }
                else
                {
                    canvasSmallSearchProcs.Visibility = Visibility.Collapsed;
                }
            }

        }

        [ScriptableMember]
        public void SearchDocuments(string searchTerm)
        {
            //documentList.Add(result);
            HtmlPage.Window.Invoke("searchDocuments", searchTerm);
        }

        [ScriptableMember]
        public void SearchDocumentsCallback(object documentArray, string searchTerm)
        {
            if (searchTerm == txtSearch.Text)
            {
                ObservableCollection<DocumentObject> docs = BLL.ParserHelper.ParseDocuments((ScriptObject)documentArray);
                searchResultDocumentsSmall.ItemsSource = docs;
                if (docs.Count > 0)
                {
                    canvasSmallSearchDocs.Visibility = Visibility.Visible;
                }
                else
                {
                    canvasSmallSearchDocs.Visibility = Visibility.Collapsed;
                }
            }
        }

        [ScriptableMember]
        public void AddSearchResult(string result)
        {
            //documentList.Add(result);
            //HtmlPage.Window.Invoke("alice", "mojo");
        }

        [ScriptableMember]
        public void fill() {
            //flowControl.SelectedIndex = 0;
        }

        [ScriptableMember]
        public void EventFileProxied(object imageID, object imageBlob, int imageLength)
        {
            //((ScriptObject)((ScriptObject)_connections.GetProperty(0)).GetProperty("connectionType")).GetProperty("colorRGBHex").ToString()
            //Maybe this will be possible one day
            //BitmapImage img = new BitmapImage();
            //img.UriSource = new Uri("http://localhost/NavAdmin/FileReader.axd?FileID=b0688003-2e87-444b-9ffe-8ff9183141e0", UriKind.Absolute);
            //testImage.Source = img;
            //testImage.Height = 50;
            //byte[] x = imageBlob.ConvertTo<Byte[]>();
        }

        private void GetProcedureReferences(ProcedureObject p)
        {
            List<string> references = new List<string>();
            foreach(ReferenceObject r in p.InboundReferences)
                references.Add(r.ProcedureOrigin);
            foreach (ReferenceObject r in p.OutboundReferences)
                references.Add(r.ProcedureDestination);
            ReferencesOut.ClearProcedures();
            ReferencesIn.ClearProcedures();
            if (references.Count < 1)
            {
                canvasDescendents.Visibility = Visibility.Collapsed;
                canvasAscendents.Visibility = Visibility.Collapsed;
                return;
            }
            object procedureArray = HtmlPage.Window.Invoke("getProcedures", string.Join("||||",references.ToArray()));
            ObservableCollection<ProcedureObject> procedures = ParserHelper.ParseProcedures((ScriptObject)procedureArray);
            for (int i = 0; i < procedures.Count; i++)
            {
                for (int j = 0; j < p.InboundReferences.Count; j++)
                {
                    if (p.InboundReferences[j].ProcedureOrigin == procedures[i].ProcedureID)
                    {
                        //add to list
                        ReferencesIn.AddProcedure(procedures[i], p.ProcedureID);
                        break;
                    }
                }
                for (int k = 0; k < p.OutboundReferences.Count; k++)
                {
                    if (p.OutboundReferences[k].ProcedureDestination == procedures[i].ProcedureID)
                    {
                        //add to list 
                        ReferencesOut.AddProcedure(procedures[i], p.ProcedureID);
                        break;
                    }
                }
            }
            ReferencesOut.NavigateToProcedure(0);
            ReferencesIn.NavigateToProcedure(0);
            //USe this as workaround to keep on top
            ReferencesOutGrid.Children.Remove(ReferencesOut);
            ReferencesOutGrid.Children.Add(ReferencesOut);
            ReferencesInGrid.Children.Remove(ReferencesIn);
            ReferencesInGrid.Children.Add(ReferencesIn);

            if (p.InboundReferences.Count > 0)
                canvasAscendents.Visibility = Visibility.Visible;
            else
                canvasAscendents.Visibility = Visibility.Collapsed;
            if (p.OutboundReferences.Count > 0)
                canvasDescendents.Visibility = Visibility.Visible;
            else
                canvasDescendents.Visibility = Visibility.Collapsed;

        }


        public void GetProcedureDiagram(string procedureID)
        {
            HtmlPage.Window.Invoke("getProcedureDiagram", procedureID);
        }

        [ScriptableMember]
        public void GetProcedureDiagramCallback(object diagram)
        {
            //Received diagram from Javascript
            ProcessDiagram(diagram);
        }
        
        public void UpdateDocuments(string procedureID)
        {
            documentList.Clear();
            HtmlPage.Window.Invoke("updateDocuments", procedureID);
        }

        [ScriptableMember]
        public void UpdateDocumentsCallback(object documentArray, string callingProcedureID)
        {
            documentList.Clear();
            ObservableCollection<DocumentObject> docs =  BLL.ParserHelper.ParseDocuments((ScriptObject)documentArray);
            if (docs.Count > 0) 
            {
                //first prune docs
                canvasDocs.Visibility = Visibility.Visible;
                foreach (DocumentObject d in docs)
                {
                    if (documentList.Any(doc => doc.DocumentID == d.DocumentID))
                        continue;
                    documentList.Add(d);
                }
            } else 
            {
                canvasDocs.Visibility = Visibility.Collapsed;
                documentList.Add(nullDocument);
            }

        }

        public void GetProcedureParents(string procedureID)
        {
            HtmlPage.Window.Invoke("getProcedureParents", procedureID);
        }

        [ScriptableMember]
        public void GetProcedureParentsCallback(object conns, string procedureID)
        {
            lastProcedureID = procedureID;
            //this will be a list of parent procedures
            ObservableCollection<ConnectionObject> connections = BLL.ParserHelper.ParseConnections((ScriptObject)conns, null);
            flowControl.ClearDiagrams();
            //remove anything that is not PointsToProcedure!=null
            int i = connections.Count - 1;
            for (; i > -1; i--)
            {
                    AddDiagramToCoverflowCache(connections[i].ProcedureOrigin.ProcedureID);
                    flowControl.AppendDiagram(connections[i].ProcedureOrigin.ProcedureID, null, false);
            }
            flowControl.AppendDiagram(procedureID, connections[i + 1].ProcedureOrigin.ProcedureID, false);
            AddDiagramToCoverflowCache(procedureID);
        }

        [ScriptableMember]
        public void AddDiagramToCoverflowCache(string procedureID)
        {
            DiagramObject d = flowControl.ProcedureExistsInDiagrams(procedureID);
            if (d == null)
                GetProcedureDiagram(procedureID);
            else if (DiagramProcessedEvent != null)
                DiagramProcessedEvent(this, d.DiagramID);

        }

        [ScriptableMember]
        public void UpdateMenuCallback(object[] procedures, string instruction)
        {
            //this will be a list of parent procedures

        }

        private void txtSearch_KeyDown(object sender, KeyEventArgs e) {
            if (e.Key == Key.Enter || e.Key == Key.Tab) {
                //procedureClickedOnce(searchEntry1.Text);
                //search(searchEntry1.Text);
                searchResultDocumentsSmall.ItemsSource = null;
                searchResultsProcedures.Clear();
                SearchDocuments(txtSearch.Text);
                SearchProcedures(txtSearch.Text);
            }
        }

        private void ResetDiagrams(string procedureID)
        {
            lastProcedureID = procedureID;
            lastProcedureIDClicked = procedureID;
            AddDiagramToCoverflowCache(procedureID);
            flowControl.ResetDiagrams(procedureID);
            flowControl.UpdateFlowByProcedure(procedureID);
        }

        private void ResetDiagrams() {
            ResetDiagrams(rootProcedureID);            
        }

        private void Menu_MenuItemClicked(object sender, SelectedMenuItemArgs e) {
            flowControl.SelectCover(e.Item.ID.ToString());
        }

        private void flowControl_MenuItemClicked(object sender, InnovationFoundry.QualityHelper.Silverlight.Controls.CoverFlow.CoverFlowControl.SelectedMenuItemArgs e) {
            //unbox
            DiagramObject d = e.Diagram;
            if (d == null)
                return;
            //update title
            //txtDiagram.Text = String.Format("Diagram: {0}", d.Title);
            txtDiagram.Text = String.Format("{0}", d.Title);
            //update procedures
            //updateProcedures(d.Procedures);
            //update documents
        }


        /// <summary>
        /// Go through history and add/fix/prune to tree
        /// </summary>
        private void restructureProcMenu() 
        {
            
        }
        
        /// <summary>
        /// Go through history and add/fix/prune
        /// </summary>
        /// <param name="proceduresToUpdate"></param>
        private void restructureProcMenu(List<ProcedureObject> proceduresToUpdate) {

        }

        private void flowControl_ProcedureClicked(object sender, InnovationFoundry.QualityHelper.Silverlight.Controls.CoverFlow.CoverFlowControl.ProcedureClickedArgs e) {
            //procedure clicked
            //check for twice
            if (lastProcedureIDClicked == e.Procedure.ProcedureID)
            {
                flowControl_ProcedureDoubleClicked(sender,e);
                return;
            }
            //highlight the focused procedure & notify javascript
            lastProcedureIDClicked = e.Procedure.ProcedureID;
            
            //update docs
            documentList.Clear();
            UpdateDocuments(e.Procedure.ProcedureID);

            //Update Procedure
            updateProcedureInfo(e.Procedure);
            //add notification
            //if (documentList.Count == 0)
            //    documentList.Add(documentNullText);

            //Show references
            GetProcedureReferences(e.Procedure);

            updateMenus();

           
        }

        private void updateProcedureInfo(ProcedureObject p)
        {
            canvasProcInfo.Visibility = Visibility.Visible;
            procInfo.Children.Clear();
            TextBlock tb = new TextBlock();
            tb.Padding = new Thickness(7,10,7,0);
            tb.Text = p.ProcedureName;
            tb.FontWeight = FontWeights.ExtraBold;
            procInfo.Children.Add(tb);
            tb = new TextBlock();
            tb.Padding = new Thickness(7, 10, 7, 0);
            tb.Text = "ID: " + p.ProcedureID;
            tb.FontWeight = FontWeights.Bold;
            procInfo.Children.Add(tb);
            tb = new TextBlock();
            tb.Padding = new Thickness(7, 10, 7, 10);
            tb.Text = p.ProcedureDescription;
            tb.HorizontalAlignment = HorizontalAlignment.Stretch;
            tb.TextWrapping = TextWrapping.Wrap;
            procInfo.Children.Add(tb);
            updateMenus();
        }

        private ProcedureObject findInProcedure(ProcedureObject proc, string procID)
        {
            if (proc.ProcedureID == procID)
                return proc;
            foreach (ProcedureObject p in proc.Children)
            {
                if (p.ProcedureID == procID)
                    return p;
                else
                    findInProcedure(p,procID);
            }
            return null;
        }


        private void updateProcedureList(DiagramObject d)
        {
            if (procedureList.Count == 0 && d.ProcedureRoot == null)
            {
                foreach (ProcedureObject p in d.Procedures)
                    procedureList.Add(p);
            } 
            else if (d.ProcedureRoot != null)
            {
                for (int i = 0; i < procedureList.Count; i++)
                {
                    ProcedureObject procFound = findInProcedure(procedureList[i], d.ProcedureRoot.ProcedureID);
                    if (procFound != null)
                    {
                        foreach (ProcedureObject p in d.Procedures)
                        {
                            if (!procFound.Children.Any(o => o.ProcedureID == p.ProcedureID) && p.ProcedureID != procFound.ProcedureID)
                            {
                                p.Parent = procFound;
                                procFound.Children.Add(p);
                            }
                        }
                        break;
                    }

                }
            }
        }

        private void documents_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {

            DocumentObject doc = treeDocs.SelectedValue as DocumentObject;
            if(doc!=null && doc!=nullDocument)
                openDocument(doc);
        }

        private void openDocument(DocumentObject doc) {
            if ((bool)HtmlPage.Window.Invoke("IsOnline") && !doc.OriginURL.StartsWith("file"))
                HtmlPage.Window.Invoke("getFileViaURL", doc.OriginURL);
            else
                HtmlPage.Window.Invoke("openDocument", doc.DocumentID);            
        }

        private void searchResultDocumentsSmall_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            DocumentObject doc = searchResultDocumentsSmall.SelectedItem as DocumentObject;
            if (doc != null)
                openDocument(doc);
        }

        private void searchResultProceduresSmall_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ProcedureObject proc = searchResultProceduresSmall.SelectedItem as ProcedureObject;
            AddDiagramToCoverflowCache(proc.ProcedureID);
            lastProcedureID = proc.ProcedureID;
            flowControl.AppendDiagram(proc.ProcedureID, null, true);
            flowControl.UpdateFlowByProcedure(proc.ProcedureID);
            updateProcedureInfo(proc);
            documentList.Clear();
            UpdateDocuments(proc.ProcedureID);
            //Used to get hierarchy
            //if (proc != null)
            //    GetProcedureParents(proc.ProcedureID);
        }
        
        private List<ProcedureObject> getProcedureHierarchy(ProcedureObject procedure)
        {
            List<ProcedureObject> hierarchy = new List<ProcedureObject>();
            hierarchy.Add(procedure);
            if (procedure != null)
            {
                hierarchy.AddRange(getProcedureHierarchy(procedure.Parent));
            }
            return hierarchy;
        }
        
        
        private void flowControl_ProcedureDoubleClicked(object sender, InnovationFoundry.QualityHelper.Silverlight.Controls.CoverFlow.CoverFlowControl.ProcedureClickedArgs e)
        {
            //disable single click-backs
            lastProcedureIDClicked = null;

            //Clear the references
            ReferencesIn.ClearProcedures();
            ReferencesOut.ClearProcedures();
            ReferencesIn.NavigateToProcedure(-1);
            ReferencesOut.NavigateToProcedure(-1);
            canvasAscendents.Visibility = Visibility.Collapsed;
            canvasDescendents.Visibility = Visibility.Collapsed;
            
            if (e.Procedure.OutboundReferences.Count > 0) {
                AddDiagramToCoverflowCache(e.Procedure.OutboundReferences[0].ProcedureDestination);
                if (e.Procedure.InboundReferences.Count < 1)
                    lastProcedureID = e.Procedure.OutboundReferences[0].ProcedureDestination;
                flowControl.AppendDiagram(e.Procedure.OutboundReferences[0].ProcedureDestination, e.Procedure.OutboundReferences[0].ProcedureOrigin, false);
                if (e.Procedure.InboundReferences.Count < 1)
                    flowControl.UpdateFlowByProcedure(e.Procedure.OutboundReferences[0].ProcedureOrigin);
            }
            if (e.Procedure.InboundReferences.Count > 0)
            {
                List<string> toPrepend = new List<string>();
                toPrepend.Add(e.Procedure.InboundReferences[0].ProcedureOrigin);
                AddDiagramToCoverflowCache(toPrepend[0]);
                lastProcedureID = toPrepend[0];
                flowControl.PrependDiagrams(toPrepend, e.Procedure.InboundReferences[0].ProcedureDestination, false);
                flowControl.UpdateFlowByProcedure(e.Procedure.InboundReferences[0].ProcedureDestination);

            }

            updateMenus();
            //AddDiagramToCoverflowCache(args.Procedure.ProcedureID);
            //lastProcedureID = args.Procedure.ProcedureID;
            //flowControl.AppendDiagram(args.Procedure.ProcedureID, args.ProcedureRelation, false);
            //flowControl.UpdateFlowByProcedure(args.Procedure.ProcedureID);
            //updateProcedureInfo(args.Procedure);
            //ReferencesOut.ClearProcedures();
            //UpdateDocuments(args.Procedure.ProcedureID);
            //expanderAscendents.Visibility = Visibility.Collapsed;
            //expanderDescendents.Visibility = Visibility.Collapsed;

        }

        private void treeProc_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            //ProcedureObject newProc = treeProc.SelectedValue as ProcedureObject;
            //if (newProc == null)
            //    return;
            //ProcedureObject oldProc = flowControl.Diagrams[flowControl.SelectedIndex].ProcedureRoot; //e.OldValue as ProcedureObject;
            //List<ProcedureObject> newProcedureHierarchy = getProcedureHierarchy(newProc);
            //List<ProcedureObject> oldProcedureHierarchy = getProcedureHierarchy(oldProc);
            //newProcedureHierarchy.Reverse();
            //oldProcedureHierarchy.Reverse();
            ////flowControl.Diagrams.Clear();
            ////GetProcedureDiagram(null);

            ////PRUNE
            //int i = 0;
            //bool pruned = false;
            //for (; i < newProcedureHierarchy.Count && i < oldProcedureHierarchy.Count; i++)
            //{
            //    if (newProcedureHierarchy[i] != oldProcedureHierarchy[i])
            //    {
            //        break;
            //    }
            //}

            //for (int k = flowControl.Diagrams.Count - 1; k >= i; k--)
            //{
            //    pruned = true;
            //    flowControl.Diagrams.RemoveAt(k);
            //}

            ////Clean the flow diagram up if pruned
            //if (pruned)
            //    flowControl.UpdateFlow();

            ////Now add in remainder new ones
            //for (int l = i; l < newProcedureHierarchy.Count; l++)
            //{
            //    GetProcedureDiagram(newProcedureHierarchy[l].ProcedureID);
            //}


            ////int newFlowIndex = flowControl.Diagrams.IndexOf(flowControl.Diagrams.First(diagram => diagram.ProcedureRoot != null && diagram.ProcedureRoot.ProcedureID == newProc.ProcedureID));
            //flowControl.SelectedIndex = newProcedureHierarchy.Count - 1;
            ////flowControl.SelectedIndex = flowControl.Diagrams.Count - 1;

        }
        private void btnFullscreen_Click(object sender, RoutedEventArgs e) {
            Application.Current.Host.Content.IsFullScreen = !Application.Current.Host.Content.IsFullScreen;
        }

        private void AppIcon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            ResetDiagrams();
        }

        private void HelpIcon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            HtmlPage.Window.Invoke("openDocumentViaCode", "HELP");         
        }



    }
}

